#include "delay.h"
#include <string.h>
#include "mbcontroller.h"// for mbcontroller defines and api
#include "modbusSlave.h"
#include "motor_priv.h"


#define MB_PORT_NUM          UART_NUM_1
#define MB_SLAVE_ADDR        22
#define MB_DEV_SPEED         921600
#define MB_TXD_PIN           17
#define MB_RXD_PIN           16
#define MB_TASK_SIZE         1024 * 4
#define MB_TASK_PRIORITY     12
#define MB_PAR_INFO_GET_TOUT (10)// Timeout for get parameter info


typedef struct ModbusSlaveRegList
{
    struct ModbusSlaveRegList *next;
    ModbusSlaveReg             regArea;
} ModbusSlaveRegList;

typedef struct
{
    TaskHandle_t        task;
    ModbusSlaveRegList *regHead;
    portMUX_TYPE        gParamLock;
    void               *mbcSlaveHandle;
} ModbusSlaveManager;

static char              *tag = "modbus";
static ModbusSlaveManager gModbusSlave;

/*从站线程*/
static void MODBUS_task(void *para)
{
    esp_err_t           res;
    mb_param_info_t     regInfo;
    ModbusSlaveRegList *head = gModbusSlave.regHead;
    ModbusSlaveRegList *next = NULL;

    while (1)
    {
        mdelay(5);
        // 检测是否有读写时间发生
        mb_event_group_t event = mbc_slave_check_event(MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD);

        if (!event)
        {
            /*时间为空直接继续下一次*/
            continue;
        }

        // 获取被写的寄存器信息
        res = mbc_slave_get_param_info(&regInfo, MB_PAR_INFO_GET_TOUT);
        if (res || (event & MB_EVENT_HOLDING_REG_RD))
        {
            // if ((event & MB_EVENT_HOLDING_REG_RD))
            // {
            //     MotorReg *rrr= regInfo.address;
            //     printf("%f\n",rrr->ua);
            // }
            /*获取失败，或者是读取寄存器的话，直接继续下一次*/
            continue;
        }

        // 处理保持寄存器的写操作
        // ESP_LOGI(tag, "addr:%d, size:%d, time:%d\n", regInfo.mb_offset, regInfo.size, regInfo.time_stamp);
        next = head;
        /*查询被操作的寄存器属于哪个模块*/
        while (next)
        {
            ModbusSlaveReg *reg = &next->regArea;
            if (regInfo.mb_offset >= reg->regAddr && regInfo.mb_offset < reg->regAddr + reg->size / 2)
            {
                xQueueSend(reg->queue, &regInfo, 0);
                // ESP_LOGI(tag, "send: %d\n", xQueueSend(reg->queue, &regInfo, 0));
                break;
            }
            next = next->next;
        }
    }
}

/*modbus从站初始化*/
void MODBUS_slaveInit(void)
{
    mb_communication_info_t       commInfo;// Modbus communication parameters
    esp_err_t                     res  = 0;
    ModbusSlaveRegList           *next = gModbusSlave.regHead;
    mb_register_area_descriptor_t regArea;

    // Initialization of Modbus controller
    res = mbc_slave_init(MB_PORT_SERIAL_SLAVE, &gModbusSlave.mbcSlaveHandle);
    if (res)
    {
        ESP_LOGE(tag, "mbc_slave_init error\n");
        return;
    }

    commInfo.mode       = MB_MODE_RTU;
    commInfo.slave_addr = MB_SLAVE_ADDR;
    commInfo.port       = MB_PORT_NUM;
    commInfo.baudrate   = MB_DEV_SPEED;
    commInfo.parity     = MB_PARITY_NONE;

    /*设置从机*/
    res = mbc_slave_setup((void *)&commInfo);
    if (res)
    {
        ESP_LOGE(tag, "mbc_slave_setup error\n");
        return;
    }

    while (next)
    {
        /*赋值*/
        regArea.type         = MB_PARAM_HOLDING;
        regArea.start_offset = next->regArea.regAddr;
        regArea.address      = next->regArea.addr;
        regArea.size         = next->regArea.size;
        /*注册寄存器*/
        res = mbc_slave_set_descriptor(regArea);
        if (res)
        {
            ESP_LOGE(tag, "reg[%d] siee[%ld] set error\n", regArea.start_offset, regArea.size);
        }
        ESP_LOGI(tag, "reg[%d] siee[%ld] set success\n", regArea.start_offset, regArea.size);
        next = next->next;
    }

    res = mbc_slave_start();
    if (res)
    {
        ESP_LOGE(tag, "mbc_slave_start error\n");
        return;
    }
    if (PIN_register(MB_TXD_PIN,PIN_TXD) || PIN_register(MB_RXD_PIN,PIN_RXD))
    {
        ESP_LOGE(tag, "pin register error\n");
        return;
    }

    uart_set_pin(MB_PORT_NUM, MB_TXD_PIN, MB_RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    ESP_LOGI(tag, "Modbus slave stack initialized.");
    ESP_LOGI(tag, "Start modbus test...");

    if (pdPASS !=
        xTaskCreate(MODBUS_task, "modbus_slave", MB_TASK_SIZE, &gModbusSlave, MB_TASK_PRIORITY, &gModbusSlave.task))
    {
        ESP_LOGE(tag, "modbus_slave task create fail\n");
    }
}

esp_err_t MODBUS_holdRegRegister(ModbusSlaveReg reg)
{
    ModbusSlaveRegList  *list = NULL;
    ModbusSlaveRegList **next = &gModbusSlave.regHead;

    /*寻找空闲链表*/
    while ((*next))
    {
        /*判断寄存器区域是否已经被注册过*/
        if ((reg.regAddr >= (*next)->regArea.regAddr &&
             reg.regAddr < (*next)->regArea.regAddr + (*next)->regArea.size) ||
            (reg.regAddr + reg.size >= (*next)->regArea.regAddr &&
             reg.regAddr + reg.size < (*next)->regArea.regAddr + (*next)->regArea.size))
        {
            ESP_LOGE(tag, "the reg area has been registed\n");
            return ESP_FAIL;
        }
        next = &((*next)->next);
    }

    list = calloc(1, sizeof(ModbusSlaveRegList));
    if (!list)
    {
        ESP_LOGE(tag, "ModbusSlaveRegList calloc error\n");
        return ESP_FAIL;
    }

    memcpy(&list->regArea, &reg, sizeof(ModbusSlaveReg));

    *next = list;

    return ESP_OK;
}

void MODBUS_holdRegUnRegister(ModbusSlaveReg reg)
{
    /*待实现...*/
    /*1.删除线程资源*/

    /*2.modbus_slave_destory*/

    /*3.根据reg查询要取消注册的是哪一个寄存器区域*/

    /*4.将寄存器区域指向它下一个链表节点*/

    /*5.初始化modbus_slave*/

    /*6.根据寄存器区域链表信息重新设置modbus寄存器*/
}
